// AbstractWindow.java
package org.zjx.core;

import com.sun.jna.platform.win32.WinDef.HWND;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.zjx.command.ICommand;
import org.zjx.util.HwndUtil;

import java.awt.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 抽象窗口基类 - 改进线程安全和生命周期管理
 */
@Slf4j
@Getter
public abstract class AbstractWindow implements IWindow {
    protected final HWND hwnd;

    protected final BlockingQueue<ICommand> commandQueue;
    private final AtomicBoolean running = new AtomicBoolean(false);
    private final AtomicBoolean shutdownRequested = new AtomicBoolean(false);
    private final AtomicReference<Thread> executionThreadRef = new AtomicReference<>();
    private final CountDownLatch terminationLatch = new CountDownLatch(1);

    private final ExecutorService commandExecutor;

    public AbstractWindow(HWND hwnd) {
        this(hwnd, 50); // 默认队列大小
    }

    public AbstractWindow(HWND hwnd, int queueCapacity) {
        if (hwnd == null) {
            throw new IllegalArgumentException("窗口句柄不能为空");
        }

        this.hwnd = hwnd;
        this.commandQueue = new LinkedBlockingQueue<>(queueCapacity);
        this.commandExecutor = Executors.newSingleThreadExecutor(r -> {
            Thread t = new Thread(r, "窗口命令执行器-" + getId());
            t.setDaemon(true);
            return t;
        });

        start();
    }

    @Override
    public Rectangle getBounds() {
        if (!HwndUtil.haveWindow(hwnd)) return null;
        return HwndUtil.getWindowRectangle(hwnd);
    }

    @Override
    public CompletableFuture<Boolean> submitCommand(ICommand command) {
        if (command == null) {
            log.error("[窗口] 不能提交空命令到: {}", getId());
            return CompletableFuture.completedFuture(false);
        }

        if (!running.get() || shutdownRequested.get()) {
            log.error("[窗口] 不能向已停止的窗口提交命令: {}", getId());
            return CompletableFuture.completedFuture(false);
        }

        if (!isValid()) {
            log.error("[窗口] 窗口已失效，不能提交命令: {}", getId());
            return CompletableFuture.completedFuture(false);
        }

        boolean offered = commandQueue.offer(command);
        if (!offered) {
            log.warn("[窗口] 命令队列已满，丢弃命令: {} -> {}", command.getCommandName(), getId());
            return CompletableFuture.completedFuture(false);
        }

        log.debug("[窗口] 命令 {} 提交到 {}", command.getCommandName(), getId());

        // 返回异步结果
        return CompletableFuture.supplyAsync(() -> {
            // 命令会在主循环中执行，这里只是跟踪提交状态
            return true;
        }, commandExecutor);
    }

    @Override
    public void run() {
        log.info("[窗口] {} 执行线程启动", getId());
        executionThreadRef.set(Thread.currentThread());

        try {
            while (running.get() && !shutdownRequested.get()) {
                try {
                    if (!isValid()) {
                        log.warn("[窗口] {} 已失效，停止处理命令", getId());
                        break;
                    }

                    ICommand command = commandQueue.poll(100, TimeUnit.MILLISECONDS);
                    if (command != null) {
                        executeCommand(command);
                    }

                } catch (InterruptedException e) {
                    if (shutdownRequested.get()) {
                        log.info("[窗口] {} 执行线程在关闭期间被中断", getId());
                        break;
                    }
                    log.warn("[窗口] {} 执行线程意外中断", getId());
                    Thread.currentThread().interrupt();
                    break;
                } catch (Exception e) {
                    log.error("[窗口] {} 执行线程错误: {}", getId(), e.getMessage(), e);
                }
            }
        } finally {
            running.set(false);
            terminationLatch.countDown();
            log.info("[窗口] {} 执行线程停止", getId());
        }
    }

    @Override
    public boolean isValid() {
        return HwndUtil.haveWindow(hwnd) && running.get();
    }

    @Override
    public void executeCommand(ICommand command) {
        if (command == null) return;

        String commandName = command.getCommandName();
        log.debug("[窗口] {} 开始执行命令: {}", getId(), commandName);

        long startTime = System.currentTimeMillis();
        boolean success = false;

        try {
            success = command.execute();
            long duration = System.currentTimeMillis() - startTime;

            if (success) {
                log.debug("[窗口] {} 完成命令: {} 耗时 {}ms", getId(), commandName, duration);
            } else {
                log.warn("[窗口] {} 命令执行失败: {} 耗时 {}ms", getId(), commandName, duration);
            }

        } catch (InterruptedException e) {
            log.warn("[窗口] {} 命令执行被中断: {}", getId(), commandName);
            Thread.currentThread().interrupt();
        } catch (Exception e) {
            long duration = System.currentTimeMillis() - startTime;
            log.error("[窗口] {} 执行命令错误: {} 耗时 {}ms", getId(), commandName, duration, e);
        }
    }

    private void start() {
        if (running.compareAndSet(false, true)) {
            Thread thread = new Thread(this, "窗口线程-" + getId());
            thread.setDaemon(true);
            thread.start();
            log.info("[窗口] {} 创建并启动", getId());
        }
    }

    @Override
    public void shutdown() {
        if (shutdownRequested.compareAndSet(false, true)) {
            log.info("[窗口] 停止: {}", getId());

            running.set(false);
            commandQueue.clear();

            Thread executionThread = executionThreadRef.get();
            if (executionThread != null && executionThread.isAlive()) {
                executionThread.interrupt();
            }

            commandExecutor.shutdown();
        }
    }

    @Override
    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
        return terminationLatch.await(timeout, unit) &&
                commandExecutor.awaitTermination(timeout, unit);
    }

    /**
     * 获取窗口状态信息
     */
    public String getStatus() {
        return String.format("Window[%s, running=%s, queueSize=%d, valid=%s]",
                getId(), running.get(), commandQueue.size(), isValid());
    }

    @Override
    protected void finalize() throws Throwable {
        try {
            if (running.get()) {
                log.warn("[窗口] {} 在finalize时仍在运行，执行紧急关闭", getId());
                shutdown();
            }
        } finally {
            super.finalize();
        }
    }
}